package com.latitech.flutter_push

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.util.Log
import androidx.annotation.NonNull
import com.alibaba.sdk.android.push.CommonCallback
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.Registrar
import io.flutter.view.FlutterView

/**
 * 推送插件
 */
class FlutterPushPlugin : MethodCallHandler, FlutterPlugin, ActivityAware, PluginRegistry.NewIntentListener {

    /**
     * 插件通道
     */
    private var channel: MethodChannel? = null

    /**
     * activity插件绑定器
     */
    private var activityBinding: ActivityPluginBinding? = null

    /**
     * 推送消息接收者
     */
    private var receiver: OpenMessageReceiver? = null

    /**
     * applicationContext
     */
    private lateinit var context: Context;

    companion object {
        private const val TAG = "FlutterPushPlugin"
    }

    /**
     * 装载插件
     */
    private fun setup(context: Context, messenger: BinaryMessenger) {
        channel = MethodChannel(messenger, "flutter_push")
        channel!!.setMethodCallHandler(this)
        receiver = OpenMessageReceiver(channel!!)
        this.context = context
        context.registerReceiver(receiver!!, receiver!!.intentFilter)
    }

    override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        setup(binding.applicationContext, binding.binaryMessenger)
        binding.flutterEngine.renderer.addIsDisplayingFlutterUiListener(object : FlutterUiDisplayListener {
            override fun onFlutterUiNoLongerDisplayed() {
            }

            override fun onFlutterUiDisplayed() {
                binding.flutterEngine.renderer.removeIsDisplayingFlutterUiListener(this)
                receiver?.handleOpenNotificationIntent(activityBinding?.activity?.intent)
            }
        })
    }

    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        if (receiver != null) {
            binding.applicationContext.unregisterReceiver(receiver!!)
        }
        receiver = null
        channel?.setMethodCallHandler(null)
        channel = null
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        activityBinding = binding
        binding.addOnNewIntentListener(this)
    }

    override fun onDetachedFromActivity() {
        activityBinding?.removeOnNewIntentListener(this)
        activityBinding = null
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        onAttachedToActivity(binding)
    }

    override fun onDetachedFromActivityForConfigChanges() {
        onDetachedFromActivity()
    }

    override fun onNewIntent(intent: Intent?): Boolean {
        receiver?.handleOpenNotificationIntent(intent)
        return false
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        when (call.method) {
            "registerPushService" -> {
                PushServiceFactory.getCloudPushService().bindAccount(call.argument("accountId"),
                    object : CommonCallback {
                        override fun onSuccess(p0: String?) {
                            Log.d(TAG, "bindAccount success $p0")
                        }

                        override fun onFailed(errorCode: String?, errorMessage: String?) {
                            Log.d(TAG, "bindAccount failed errorCode:$errorCode errorMessage:$errorMessage")
                        }
                    })

                result.success(null)
            }
            "unregisterPushService" -> {
                PushServiceFactory.getCloudPushService().unbindAccount(
                    object : CommonCallback {
                        override fun onSuccess(p0: String?) {
                            Log.d(TAG, "unbindAccount success $p0")
                        }

                        override fun onFailed(errorCode: String?, errorMessage: String?) {
                            Log.d(TAG, "unbindAccount failed errorCode:$errorCode errorMessage:$errorMessage")
                        }
                    })
                result.success(null)
            }
        }
    }
}

/**
 * 用于接收推送消息打开事件的接口
 *
 * @property channel flutter通道
 */
class OpenMessageReceiver(private val channel: MethodChannel) : BroadcastReceiver() {

    /**
     * 事件类型过滤器
     */
    val intentFilter = IntentFilter().apply {
        addAction(PLUGIN_OPEN_NOTIFICATION_ACTION)
        addAction(PLUGIN_RECEIVE_MESSAGE_ACTION)
        addAction(PLUGIN_RECEIVE_NOTIFICATION_ACTION)
    }

    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            PLUGIN_OPEN_NOTIFICATION_ACTION -> handleOpenNotificationIntent(intent)
            PLUGIN_RECEIVE_NOTIFICATION_ACTION -> handleReceiveNotificationIntent(intent)
            PLUGIN_RECEIVE_MESSAGE_ACTION -> handleReceiveMessageIntent(intent)
        }
    }

    /**
     *  处理打开推送通知事件
     *
     *  @param intent 携带推送数据的Intent
     */
    fun handleOpenNotificationIntent(intent: Intent?) {
        val extra = intent?.getBundleExtra(PLUGIN_PUSH_EXTRAS)

        if (extra != null) {
            channel.invokeMethod("openNotification", extra.getString("extraMap"))
        }
    }

    /**
     *  处理接收到推送通知事件
     *
     *  @param intent 携带推送数据的Intent
     */
    private fun handleReceiveNotificationIntent(intent: Intent) {
        val extra = intent.getBundleExtra(PLUGIN_PUSH_EXTRAS)

        if (extra != null) {
            channel.invokeMethod("receiveNotification", extra.getString("extraMap"))
        }
    }

    /**
     * 处理接收到透传消息事件
     *
     * @param intent 携带推送数据的Intent
     */
    private fun handleReceiveMessageIntent(intent: Intent) {
        val extra = intent.getBundleExtra(PLUGIN_PUSH_EXTRAS)

        if (extra != null) {
            channel.invokeMethod(
                "receiveMessage", mapOf(
                    "id" to extra.getString("id"),
                    "title" to extra.getString("title"),
                    "content" to extra.getString("content")
                )
            )
        }
    }
}

/**
 * 存放Intent中的额外参数
 */
const val PLUGIN_PUSH_EXTRAS = "plugin_push_extras"

/**
 * 打开推送通知事件
 */
const val PLUGIN_OPEN_NOTIFICATION_ACTION = "plugin_open_notification_action"

/**
 * 收到推送通知事件
 */
const val PLUGIN_RECEIVE_NOTIFICATION_ACTION = "plugin_receive_notification_action"

/**
 * 收到透传消息事件
 */
const val PLUGIN_RECEIVE_MESSAGE_ACTION = "plugin_receive_message_action"
